//
// Created by cmo on 2022/5/14.
//

#include <unistd.h>
#include "util.h"
#include <pthread.h>

extern JavaVM* g_vm;//如果已经在其他.cpp定义了，直接通过extern使用全局变量

/**
 * 因为需要回调Java层的方法，而在C/C++层回调Java方法需要一个对应的Java Class字节码对象，所以需要传递过来
 */
struct JavaContext {
    jobject instance;
};

/**
 * 创建Native线程，因为需要通过反射调用Java层的回调方法，所以需要获取到对应的env，这里就是前面为什么要获取JavaVM 实例的原因了，通过JavaVM实例可以调用AttachCurrentThread函数获取对应的env
通过上一步获取到的env 反射方式调用Java的方法，最后使用完毕之后再线程函数中JavaVM实例调用DetachCurrentThread 函数并且return 0
 * @param args
 * @return
 */
void* interactWithJava(void* args)
{
    JNIEnv* env= nullptr;
    LOGE("【通过JavaVM传入env执行AttachCurrentThread把env 附加到虚拟机，附加成功之后env就被赋值了】");
    //等价于_vm不等于NULL
    if(g_vm)
    {
        jint ret = g_vm->AttachCurrentThread(&env, 0); // native线程附加到Java 虚拟机,附加成功之后env就被赋值了
        if(ret==JNI_OK)
        {
            LOGE("【AttachCurrentThread 成功，env赋值】");
            JavaContext* context=static_cast<JavaContext*>(args);
            if(context)
            {
                sleep(2);
                //获得MainActivity的class对象
                jclass clz = env->GetObjectClass(context->instance);
                //com.crazymo.jni.MainActivity
                //！！！！java.lang.ClassNotFoundException: Didn't find class "com.crazymo.ndk.jni.Blog" on path: DexPathList[[directory "."],nativeLibraryDirectories=[/system/lib64, /vendor/lib64, /product/lib64, /system/lib64, /vendor/lib64, /product/lib64]]为什么找不到？因为线程里attach时的jni 的env中 findclass用的BootClassLoader只能找到系统的类，不能找到自己编写的类。
                ///jclass clz = env->FindClass("com/crazymo/jni/MainActivity");
                if (clz) {
                    // 反射获得方法
                    jmethodID updui_method = env->GetMethodID(clz, "updateUI", "()V");
                    if (updui_method) {
                        LOGE("【通过反射找到要回调的Java方法的methodID并调用】");
                        env->CallVoidMethod(context->instance, updui_method);
                        env->DeleteGlobalRef(context->instance);
                        delete (context);
                        context = 0;
                    }
                }
            }
        }else{
            LOGE("CONTEXT IS NULL");
        }
    }
    g_vm->DetachCurrentThread();
    return 0;//线程函数必须记得返回0

}

extern "C"
JNIEXPORT void JNICALL
Java_com_crazymo_jni_ProcessJavaDataHelper_runNativeCallJava(JNIEnv *env, jobject thiz,jobject obj) {
    //注意这里的instance 代表的是runNativeCallJava所属类的实例
    LOGE("在C/C++ 层创建Native线程...")
    pthread_t pid;
    //必须把传递过来的对象保存为全局引用，然后才能传递到另一个线程使用，否则报attempt to use stale WeakGlobal 0x3 (should be 0x7)
    JavaContext* ctx = new JavaContext;
    ctx->instance = env->NewGlobalRef(obj);
    pthread_create(&pid, 0, interactWithJava, ctx);//创建并启动Native线程
}